package com.example.easyscript.common.minio;


import com.example.easyscript.common.minio.bo.MinioConstants;
import com.example.easyscript.common.minio.bo.MinioItem;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Bucket;
import io.minio.messages.Item;
import lombok.AllArgsConstructor;
import lombok.NoArgsConstructor;

import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

/**
 * minio 交互类
 */
@NoArgsConstructor
@AllArgsConstructor
public class MinioTemplate {

    private String endpoint;
    private String accessKey;
    private String secretKey;


    /**
     * 创建bucket
     *
     * @param bucketName bucket名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#makeBucket
     */
    public void createBucket(String bucketName) throws Exception {
        MinioClient client = getMinioClient();
        if (!client.bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            client.makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());
        }
    }

    /**
     * 获取全部bucket
     * <p>
     * https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    public List<Bucket> getAllBuckets() throws Exception {
        return getMinioClient().listBuckets();
    }

    /**
     * @param bucketName bucket名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#listBuckets
     */
    public Optional<Bucket> getBucket(String bucketName) throws Exception {
        return getMinioClient().listBuckets().stream().filter(b -> b.name().equals(bucketName)).findFirst();
    }

    /**
     * @param bucketName bucket名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeBucket
     */
    public void removeBucket(String bucketName) throws Exception {
        getMinioClient().removeBucket(RemoveBucketArgs.builder().bucket(bucketName).build());
    }

    /**
     * 根据文件前置查询文件
     *
     * @param bucketName bucket名称
     * @param prefix     前缀
     * @param recursive  是否递归查询
     * @return
     * @throws Exception
     */
    public List<MinioItem> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) throws Exception {
        List objectList = new ArrayList();
        Iterable<Result<Item>> objectsIterator = getMinioClient()
                .listObjects(ListObjectsArgs.builder().bucket(bucketName).prefix(prefix).recursive(recursive).build());

        while (objectsIterator.iterator().hasNext()) {
            objectList.add(objectsIterator.iterator().next().get());
        }
        return objectList;
    }

    /**
     * 获取文件外链
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param expires    过期时间 <=7
     * @return url
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject
     */
    public String getObjectURL(String bucketName, String objectName, Integer expires) throws Exception {
        return getMinioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(objectName).expiry(expires).build());
    }

    /**
     * 获取文件外链
     * 默认7天有效期
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return url
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject
     */
    public String getObjectURL(String bucketName, String objectName) throws Exception {
        return getMinioClient().getPresignedObjectUrl(GetPresignedObjectUrlArgs.builder().method(Method.GET).bucket(bucketName).object(objectName).build());
    }

    /**
     * 获取文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @return 二进制流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#getObject
     */
    public InputStream getObject(String bucketName, String objectName) throws Exception {
        return getMinioClient().getObject(GetObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 上传文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @param stream     文件流
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream) throws Exception {
        if (!MinioConstants.validBucket(bucketName))
            throw new Exception("非法Bucket");
        //假设不存在 bucket名称，程序创建 bucket名称,不需要手动创建
        createBucket(bucketName);
        getMinioClient().putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, Long.valueOf(stream.available()), -1).contentType("application/octet-stream").build());
    }

    /**
     * 上传文件
     *
     * @param bucketName  bucket名称
     * @param objectName  文件名称
     * @param stream      文件流
     * @param size        大小
     * @param contextType 类型
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#putObject
     */
    public void putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) throws Exception {
        //假设不存在 bucket名称，程序创建 bucket名称,不需要手动创建
        createBucket(bucketName);
        getMinioClient().putObject(PutObjectArgs.builder().bucket(bucketName).object(objectName).stream(stream, size, -1).contentType(contextType).build());
    }

    /**
     * 获取文件信息
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#statObject
     */
    public StatObjectResponse getObjectInfo(String bucketName, String objectName) throws Exception {
        return getMinioClient().statObject(StatObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }

    /**
     * 删除文件
     *
     * @param bucketName bucket名称
     * @param objectName 文件名称
     * @throws Exception https://docs.minio.io/cn/java-client-api-reference.html#removeObject
     */
    public void removeObject(String bucketName, String objectName) throws Exception {
        getMinioClient().removeObject(RemoveObjectArgs.builder().bucket(bucketName).object(objectName).build());
    }


    /**
     * 获取minio 原生客户端
     *
     * @return
     */
    public MinioClient getMinioClient() {
        return MinioClient.builder().endpoint(endpoint).credentials(accessKey, secretKey).build();
    }
}
